﻿using System.Globalization;
using System.Net.Http.Json;
using System.Text;
using Devonline.AspNetCore;
using Devonline.CloudService.Xfyun.IdCard;
using Devonline.Entity;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Devonline.CloudService.Xfyun;

/// <summary>
/// 身份证在线识别服务
/// </summary>
public class IdCardService<TDbContext>(
    ILogger<IdCardService<TDbContext>> logger,
    IIdCardEndpoint endpoint,
    IHttpClientFactory httpClientFactory,
    IFileService fileService,
    IDataWithAttachmentService<TDbContext, Entity.IdCard> dataService) :
    IIdCardService where TDbContext : DbContext
{
    private readonly ILogger<IdCardService<TDbContext>> _logger = logger;
    private readonly IIdCardEndpoint _endpoint = endpoint;
    private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
    private readonly IFileService _fileService = fileService;
    private readonly IDataWithAttachmentService<TDbContext, Entity.IdCard> _dataService = dataService;

    /// <summary>
    /// 从身份证照片识别并获取身份证信息
    /// </summary>
    /// <param name="attachments"></param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    public async Task<IdCardViewModel> GetIdCardInformationAsync(ICollection<Attachment> attachments)
    {
        if (attachments.Count < 2 || attachments.Any(x => string.IsNullOrWhiteSpace(x.Path)))
        {
            throw new BadHttpRequestException("请同时提交身份证正反面照片!");
        }

        #region 调用接口, 获取身份证信息
        var userName = _dataService.UserName;
        var idCard = new IdCardViewModel { Attachments = [] };
        foreach (var attachment in attachments)
        {
            ArgumentNullException.ThrowIfNull(attachment.Path);

            _logger.LogDebug($"用户 {userName} 提交身份证照片 {attachment.Name} 将获取身份证信息!");
            var data = await GetIdCardInformationAsync(_fileService.GetAttachmentPath(attachment.Path));
            _logger.LogInformation($"用户 {userName} 提交身份证照片 {attachment.Name} 获取身份证信息成功!");

            if (data.Type == IdCardData.IDCARD_TYPE_FRONT)
            {
                try
                {
                    //身份证正面
                    if (string.IsNullOrWhiteSpace(data.IdCode))
                    {
                        _logger.LogError($"用户 {userName} 身份证正面照片 {attachment.Name} 未能获取身份证号码!");
                        throw new BadHttpRequestException("身份证正面照片验证失败, 请重新提交!");
                    }

                    if (!data.IdCode.IsIdCode())
                    {
                        _logger.LogError($"用户 {userName} 身份证正面照片 {attachment.Name} 获取的身份证号码 {data.IdCode} 未能通过验证!");
                        throw new BadHttpRequestException($"身份证正面照片识别的身份证号码 {data.IdCode} 未能通过验证, 请重新提交!");
                    }

                    idCard.Name = data.Name!;
                    idCard.Gender = data.Sex?.GetEnumValueByDisplayName<Gender>() ?? Gender.Unknown;
                    idCard.IdCode = data.IdCode;
                    idCard.Nation = (data.Nation + "族").GetEnumValueByDisplayName<Nation>();
                    idCard.Address = data.Address;
                    idCard.FrontImage = attachment.Path;
                    attachment.BusinessKey = idCard.Id;
                    attachment.BusinessType = nameof(IdCard) + CHAR_DOT + nameof(Entity.IdCard.FrontImage);

                    idCard.Attachments.Add(attachment);
                    if (!string.IsNullOrWhiteSpace(data.BirthDay))
                    {
                        try
                        {
                            //获取出生日期
                            idCard.Birthday = Convert.ToDateTime(data.BirthDay, new DateTimeFormatInfo { ShortDatePattern = DEFAULT_DATE_FORMAT_CN });
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, $"用户 {userName} 出生日期解析失败, " + ex.GetMessage());
                            idCard.Birthday = idCard.IdCode?.GetBirthdayFromIdCode();
                        }
                    }

                    if (data.HeadPortrait is null || string.IsNullOrWhiteSpace(data.HeadPortrait.Image))
                    {
                        _logger.LogWarning($"用户 {userName} 身份证头像解析失败, 未收到头像图片数据!");
                    }
                    else
                    {
                        try
                        {
                            //获取并保存身份证头像
                            var bytes = Convert.FromBase64String(data.HeadPortrait.Image);
                            var headImage = new Attachment
                            {
                                ContentType = ContentType.Jpeg,
                                Extension = DEFAULT_IMAGE_FILE_EXTENSION,
                                Length = bytes.Length,
                                Name = nameof(idCard.HeadImage) + DEFAULT_IMAGE_FILE_EXTENSION,
                                Path = _fileService.GetTempFileName(DEFAULT_IMAGE_FILE_EXTENSION),
                                BusinessKey = idCard.Id,
                                BusinessType = nameof(IdCard) + CHAR_DOT + nameof(Entity.IdCard.HeadImage)
                            };

                            idCard.HeadImage = headImage.Path;
                            var fileName = _fileService.GetAttachmentPath(headImage.Path);
                            await File.WriteAllBytesAsync(fileName, bytes);
                            idCard.Attachments.Add(headImage);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, $"用户 {userName} 身份证头像解析失败, " + ex.GetMessage());
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"用户 {userName} 身份证正面照片 {attachment.Name} 获取身份证信息失败, " + ex.GetMessage());
                    throw ex switch
                    {
                        BadHttpRequestException bex => bex,
                        _ => new BadHttpRequestException("身份证正面照片验证失败, 请重新提交!"),
                    };
                }
            }
            else if (data.Type == IdCardData.IDCARD_TYPE_BACK)
            {
                try
                {
                    //身份证反面
                    attachment.BusinessType = nameof(IdCard) + CHAR_DOT + nameof(Entity.IdCard.BackImage);
                    idCard.BackImage = attachment.Path;
                    idCard.IssuedBy = data.IssuedBy;
                    if (!string.IsNullOrWhiteSpace(data.Validity))
                    {
                        var dates = data.Validity.Split(CHAR_HLINE);
                        if (dates.IsNotNullOrEmpty() && dates.Length == 2)
                        {
                            var dateTimeFormat = new DateTimeFormatInfo { ShortDatePattern = "yyyy.MM.dd" };
                            idCard.Start = Convert.ToDateTime(dates[0], dateTimeFormat);
                            idCard.End = Convert.ToDateTime(dates[1], dateTimeFormat);
                        }
                    }

                    idCard.Attachments.Add(attachment);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"用户 {userName} 身份证反面照片 {attachment.Name} 获取身份证信息失败, " + ex.GetMessage());
                    throw new BadHttpRequestException("身份证反面照片验证失败, 请重新提交!");
                }
            }
        }
        #endregion

        return idCard;
    }
    /// <summary>
    /// 使用 idCode 获取已存在的 IdCard
    /// </summary>
    /// <param name="idCode">身份证号</param>
    /// <returns></returns>
    public async Task<Entity.IdCard?> GetByIdCodeAsync(string idCode) => await _dataService.FirstOrDefaultAsync(x => x.IdCode == idCode);
    /// <summary>
    /// 保存身份证信息, 可带附件
    /// </summary>
    /// <param name="viewModel">身份证信息</param>
    /// <param name="context">数据操作上下文</param>
    /// <returns></returns>
    public async Task<Entity.IdCard> SaveAsync(IdCardViewModel viewModel, DataServiceContext? context = null)
    {
        //保存到数据库, 但保存前, 先查询重复
        var entitySet = (Entity.IdCard)viewModel;
        var idCard = await GetByIdCodeAsync(entitySet.IdCode);
        if (idCard is null)
        {
            idCard = await _dataService.AddAsync(entitySet, context);
        }
        else
        {
            //修正身份证上的信息
            entitySet.Id = idCard.Id;
            entitySet.CopyTo(idCard, _dataService.GetAdapterConfig());
            await _dataService.UpdateAsync(idCard, context);
        }

        return idCard;
    }

    /// <summary>
    /// 根据身份证照片, 识别并获取身份证信息
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    private async Task<IdCardData> GetIdCardInformationAsync(string path)
    {
        ArgumentNullException.ThrowIfNull(_endpoint.Host);
        path = (await _fileService.GetImageCropFileAsync(path, _endpoint.ImageLimit))!;

        var body = File.ReadAllBytes(path);
        var base64 = Convert.ToBase64String(body);
        using var request = new HttpRequestMessage(System.Net.Http.HttpMethod.Post, _endpoint.Host);
        request.AddRequestHeaders(_endpoint, new IdCardParam());
        using (request.Content = new StringContent($"image={base64}", Encoding.UTF8, ContentType.FormUrlencoded))
        {
            using var httpClient = _httpClientFactory.CreateClient();
            using var httpResponse = await httpClient.SendAsync(request);
            if (httpResponse.IsSuccessStatusCode)
            {
                var response = await httpResponse.Content.ReadFromJsonAsync<ResponseData<IdCardData>>();
                if (response is null || response.Data is null)
                {
                    var result = await httpResponse.Content.ReadAsStringAsync();
                    throw new BadHttpRequestException("身份证识别接口调用成功, 但是数据返回值转换错误: " + result);
                }

                return response.Data;
            }

            throw new BadHttpRequestException("身份证识别失败, 请重试!");
        }
    }
}